<template>
  <view class="chat-container">
    <!-- 聊天记录区域 -->
    <view class="message-list">
      <view style="flex-grow: 1; flex-shrink: 1"></view>
      <view class="list">
        <view class="item" :class="[item.type]" v-for="item in messages">
          <view class="user" v-if="item.type === 'user'">
            <view class="text">
              {{ item.content }}
            </view>
          </view>
          <view class="ai" v-if="item.type === 'ai'">
            <view class="text">
              {{ item.content }}
            </view>
          </view>
          <view class="promote" v-if="item.type === 'promote'">
            <view
              @click="postPromote(promote.content)"
              class="text"
              v-for="promote in item.list"
            >
              {{ promote.content }}
            </view>
          </view>
        </view>
      </view>
    </view>

    <!-- 输入框区域 -->
    <view class="input-container">
      <input
        v-model="message"
        class="input-box"
        placeholder="请输入消息"
        :disabled="isSending"
      />
      <button @click="sendMessage" class="send-btn" :disabled="isSending">
        发送
      </button>
    </view>
  </view>
</template>

<script>
import encoding from '@/tool/encoding.js'
export default {
  data() {
    return {
      isComplete: true,
      messages: [], // 消息列表
      message: '制定一份适合初学者的前端开发职业规划', // 当前输入的消息
      isSending: false, // 是否正在发送消息
      secretKey:
        'pat_dC87V7t7ajNL7mtmZMcoINYtg2PG1UAuyubDiit2vnMxksnWVOraVfp0eFCzlYsR',
      isDone: true,
    }
  },
  onLoad() {
    let index = 0
    this.message.push({
      type: 'ai',
      content: '嗨，你好！我AI面试官擅长评估他人表现，能给你专业反馈。',
    })
    this.messages.push({
      type: 'promote',
      list: [
        {
          content: '请描述一下你的优点。',
        },
        {
          content: '讲讲你最大的挑战是什么？',
        },
        {
          content: '说说你的职业规划。',
        },
      ],
    })
  },
  methods: {
    sendMessage() {
      this.isDone = false
      const text = this.message
      this.message = ''
      this.messages.push({
        type: 'user',
        content: text,
      })
      const index = this.messages.push({
        type: 'ai',
        content: '',
      })
      const index2 = this.messages.push({
        type: 'promote',
        list: [],
      })
      if (!this.isComplete) {
        return uni.showToast({
          title: '对话还未完成',
          icon: 'none',
        })
      }
      const requestTask = uni.request({
        url: 'https://api.coze.cn/v3/chat?conversation_id',
        method: 'POST',
        // #ifdef MP-WEIXIN
        enableChunked: true,
        //#endif
        header: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.secretKey}`,
        },
        data: {
          stream: true,
          bot_id: '7490415700864417807',
          user_id: uni.getStorageSync('token'),
          additional_messages: [
            ...this.messages
              .filter((item) => item.type === 'user' || item.type === 'ai')
              .map((item) => {
                if (item.type === 'user') {
                  return {
                    role: 'user',
                    content: item.content,
                    content_type: 'text',
                  }
                } else {
                  return {
                    role: 'assistant',
                    content: item.content,
                    content_type: 'text',
                  }
                }
              }),
            {
              role: 'user',
              content: text,
              content_type: 'text',
              type: 'answer',
            },
          ],
        },
        success: (res) => {
          console.log(res)
        },
      })
      // #ifdef MP-WEIXIN
      requestTask.onChunkReceived((res) => {
        let chunkText = this.decodeUint8Array(res.data)
        const result = this.parseSSEMessages(chunkText)

        result.forEach((item) => {
          if (
            item.event === 'conversation.message.delta' &&
            item.data.type === 'answer'
          ) {
            this.messages[index - 1].content += item.data.content
          }
          if (
            item.event === 'conversation.message.completed' &&
            item.data.type === 'follow_up'
          ) {
            this.messages[index2 - 1].list.push({
              content: item.data.content,
            })
          }
          if (item.event === 'done') {
            this.isDone = true
            console.log(this.messages)
          }
        })
      })
      //#endif
    },
    getRetrieve(conversation_id, chat_id) {
      uni.request({
        url: 'https://api.coze.cn/v3/chat/retrieve',
        header: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.secretKey}`,
        },
        data: {
          conversation_id,
          chat_id,
        },
        success: (res) => {
          const data = res.data
          if (data?.data?.status !== 'completed') {
            setTimeout(() => {
              this.getRetrieve(conversation_id, chat_id)
            }, 200)
          } else {
            this.getMessageList(conversation_id, chat_id)
          }
        },
        fail: () => {
          uni.showToast({
            title: '接受信息失败',
            icon: 'error',
          })
          this.isComplete = true
        },
      })
    },
    getMessageList(conversation_id, chat_id) {
      uni.request({
        url: 'https://api.coze.cn/v3/chat/message/list',
        header: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.secretKey}`,
        },
        data: {
          conversation_id,
          chat_id,
        },
        success: (res) => {
          const data = res.data
          if (data.data) {
            const follow_up_list = {
              type: 'promote',
              list: [],
            }
            data.data.forEach((item) => {
              if (item.type === 'answer') {
                this.messages.push({
                  type: 'ai',
                  content: item.content,
                })
              }
              if (item.type === 'follow_up') {
                follow_up_list.list.push({
                  content: item.content,
                })
              }
            })
            if (follow_up_list.list.length) {
              this.messages.push(follow_up_list)
            }
          }
        },
        complete: () => {
          this.isComplete = true
        },
      })
    },
    postPromote(text) {
      this.message = text
      this.sendMessage()
    },
    decodeUint8Array(uint8Array) {
      const data16 = this.buf2hex(uint8Array)
      const requestData = this.hexToStr(data16)
      return requestData
    },
    buf2hex(arrayBuffer) {
      return Array.prototype.map
        .call(new Uint8Array(arrayBuffer), (x) =>
          ('00' + x.toString(16)).slice(-2)
        )
        .join('')
    },
    /**
     * 十六进制字符串转中文
     * @param {String} hex 为十六进制字符串
     * @return {String} 包含中文的字符串
     */
    hexToStr(hex) {
      // 去掉字符串首尾空格
      let trimedStr = hex.trim()
      // 判断trimedStr前两个字符是否为0x，如果是则截取从第三个字符及后面所有，否则返回全部字符
      let rawStr =
        trimedStr.substr(0, 2).toLowerCase() === '0x'
          ? trimedStr.substr(2)
          : trimedStr
      // 得到rawStr的长度
      let len = rawStr.length
      // 如果长度不能被2整除，那么传入的十六进制值有误，返回空字符
      if (len % 2 !== 0) {
        return ''
      }
      let curCharCode // 接收每次循环得到的字符
      let resultStr = [] // 存转换后的十进制值数组
      for (let i = 0; i < len; i = i + 2) {
        curCharCode = parseInt(rawStr.substr(i, 2), 16)
        resultStr.push(curCharCode)
      }
      // encoding为空时默认为utf-8
      let bytesView = new Uint8Array(resultStr) // 8 位无符号整数值的类型化数组
      let str = new encoding.TextDecoder().decode(bytesView)
      return str
    },
    parseSSEMessages(message) {
      // First split the entire message into individual SSE messages
      const rawMessages = message.split(/\n\n+/)
      const parsedMessages = []

      for (const rawMessage of rawMessages) {
        // Skip empty messages
        if (!rawMessage.trim()) continue

        // Check for the special done event
        if (rawMessage === 'event:done\ndata:"[DONE]"') {
          parsedMessages.push({
            event: 'done',
            data: '[DONE]',
          })
          continue
        }

        // Parse individual message
        const parts = rawMessage.split('\n')
        let eventType = 'message' // default event type
        let data = null

        for (const part of parts) {
          if (part.startsWith('event:')) {
            eventType = part.substring(6).trim()
          } else if (part.startsWith('data:')) {
            const dataStr = part.substring(5).trim()
            try {
              data = JSON.parse(dataStr)
            } catch (e) {
              // If JSON parsing fails, keep the raw string
              data = dataStr
            }
          }
        }

        if (eventType || data !== null) {
          parsedMessages.push({
            event: eventType,
            data,
          })
        }
      }

      return parsedMessages
    },
  },
}
</script>

<style scoped lang="scss">
/* 页面容器 */
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  // #ifdef H5
  height: calc(100vh - 44px);
  //#endif
  background-color: #f0f0f0;
}

/* 消息列表 */
.message-list {
  flex: 1;
  padding: 10px;
  overflow-y: auto;
  background-color: #fff;
  border-bottom: 1px solid #ddd;
  display: flex;
  flex-direction: column-reverse;

  .list {
    display: flex;
    flex-direction: column;
    gap: 25rpx 0;

    .item {
      display: flex;

      &.user {
        justify-content: flex-end;

        .user {
          max-width: 500rpx;
        }
      }

      &.ai {
        .ai {
          max-width: 500rpx;

          .text {
            background-color: #ddd;
            color: #007aff;
          }
        }
      }

      .text {
        padding: 10rpx 15rpx;
        background-color: #007aff;
        color: #fff;
        border-radius: 10rpx;
        white-space: pre-wrap;
      }

      .promote {
        padding-top: 30rpx;
        display: flex;
        flex-wrap: wrap;
        gap: 25rpx;

        .text {
          border: 1rpx solid #ccc;
          background-color: #fff;
          color: #000;
        }
      }
    }
  }
}

.message {
  max-width: 70%;
  padding: 8px 12px;
  border-radius: 15px;
  margin-bottom: 10px;
  font-size: 14px;
  line-height: 1.5;
}

.message.user {
  background-color: #007aff;
  color: white;
  align-self: flex-end;
  margin-left: auto;
}

.message.other {
  background-color: #e1e1e1;
  color: #333;
  align-self: flex-start;
}

.message-text {
  word-wrap: break-word;
}

/* 输入区域 */
.input-container {
  display: flex;
  padding: 10px;
  background-color: #fff;
  border-top: 1px solid #ddd;
}

.input-box {
  flex: 1;
  height: 40px;
  padding: 0 10px;
  border-radius: 20px;
  border: 1px solid #ddd;
  font-size: 14px;
  background-color: #f9f9f9;
}

.send-btn {
  margin-left: 10px;
  padding: 0 15px;
  height: 40px;
  border-radius: 20px;
  background-color: #007aff;
  color: white;
  font-size: 14px;
  border: none;
  cursor: pointer;
  transition: background-color 0.3s;
}

.send-btn:disabled {
  background-color: #b0b0b0;
}

.send-btn:hover:not(:disabled) {
  background-color: #005bb5;
}
</style>
